#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
简易文件分享工具 - 简化版
这个版本使用最少的依赖，兼容Python 2.7和Python 3.x
"""

import os
import sys
import socket

# 判断Python版本
PY3 = sys.version_info[0] == 3

if PY3:
    from http.server import HTTPServer, SimpleHTTPRequestHandler
    import urllib.parse as urlparse
else:
    # Python 2 兼容
    from BaseHTTPServer import HTTPServer
    from SimpleHTTPServer import SimpleHTTPRequestHandler
    import urllib as urlparse
    input = raw_input

# 常量定义
PORT = 8000
UPLOAD_DIR = "uploads"

# 确保上传目录存在
if not os.path.exists(UPLOAD_DIR):
    os.makedirs(UPLOAD_DIR)

# 获取本机IP地址
def get_local_ip():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except:
        return "127.0.0.1"

# 自定义HTTP处理器
class FileShareHandler(SimpleHTTPRequestHandler):
    def translate_path(self, path):
        """将URL路径转换为本地文件路径"""
        # 去除URL参数
        path = path.split('?', 1)[0]
        path = path.split('#', 1)[0]
        
        # 解码路径中的转义字符
        if PY3:
            path = urlparse.unquote(path)
        else:
            path = urlparse.unquote(path).decode('utf-8')
        
        # 基本的安全检查：不允许访问上层目录
        if path.startswith('/..') or '/../' in path:
            return os.path.join(os.getcwd(), 'index.html')
        
        # 将根路径映射到uploads目录
        path = path.strip('/')
        if not path:
            return os.path.join(os.getcwd(), 'index.html')
        else:
            return os.path.join(os.getcwd(), UPLOAD_DIR, path)
    
    def list_directory(self, path):
        """生成目录列表页面"""
        try:
            file_list = os.listdir(UPLOAD_DIR)
        except OSError:
            self.send_error(404, "没有找到目录")
            return None
        
        file_list.sort(key=lambda a: a.lower())
        
        # 创建HTML页面
        page = self.generate_page(file_list)
        
        # 发送响应
        encoded = page.encode('utf-8') if PY3 else page.encode('utf-8')
        self.send_response(200)
        self.send_header("Content-type", "text/html; charset=utf-8")
        self.send_header("Content-Length", str(len(encoded)))
        self.end_headers()
        
        # 发送页面内容
        if PY3:
            self.wfile.write(encoded)
        else:
            self.wfile.write(encoded)
        return None
    
    def do_GET(self):
        """处理GET请求"""
        if self.path == '/':
            # 显示主页
            self.path = '/index.html'
            return SimpleHTTPRequestHandler.do_GET(self)
        elif self.path.startswith('/uploads/'):
            # 直接访问文件
            path = self.translate_path(self.path)
            if os.path.isfile(path):
                return SimpleHTTPRequestHandler.do_GET(self)
        elif self.path.startswith('/delete/'):
            # 删除文件
            filename = urlparse.unquote(self.path[8:])
            if PY3:
                pass # 已经是UTF-8字符串
            else:
                filename = filename.decode('utf-8')
            
            # 验证文件名安全性
            filename = os.path.basename(filename)
            file_path = os.path.join(UPLOAD_DIR, filename)
            
            if os.path.exists(file_path) and os.path.isfile(file_path):
                os.remove(file_path)
                print(f"已删除文件: {filename}")
            
            # 重定向回主页
            self.send_response(303)
            self.send_header('Location', '/')
            self.end_headers()
            return
        
        # 默认显示文件列表
        self.list_directory(UPLOAD_DIR)
    
    def do_POST(self):
        """处理POST请求 - 文件上传"""
        if self.path == '/upload':
            # 获取内容类型和分界线
            content_type = self.headers['content-type']
            if not content_type:
                self.send_error(400, "错误的请求：缺少Content-Type")
                return
            
            # 检查是否是multipart表单
            if not content_type.startswith('multipart/form-data'):
                self.send_error(400, "错误的请求：需要multipart/form-data")
                return
            
            # 获取表单分界线
            boundary = content_type.split('=')[1].strip()
            boundary = boundary.encode('utf-8') if PY3 else boundary
            
            # 读取请求体内容长度
            content_length = int(self.headers['content-length'])
            
            # 读取全部内容
            post_data = self.rfile.read(content_length)
            
            # 处理文件上传
            try:
                self.save_uploaded_file(post_data, boundary)
                
                # 重定向回主页
                self.send_response(303)
                self.send_header('Location', '/')
                self.end_headers()
            except Exception as e:
                self.send_error(500, f"服务器错误: {str(e)}")
        else:
            self.send_error(404, "找不到页面")
    
    def save_uploaded_file(self, post_data, boundary):
        """解析multipart表单数据并保存文件"""
        # 分界线标记
        boundary = b'--' + boundary
        boundary_end = boundary + b'--'
        
        # 寻找第一个分界线
        start = post_data.find(boundary)
        if start == -1:
            raise ValueError("未找到表单分界线")
        
        # 寻找文件内容
        while start != -1:
            # 寻找下一个分界线
            end = post_data.find(boundary, start + len(boundary))
            if end == -1:
                # 检查是否是最后的分界线
                end = post_data.find(boundary_end, start + len(boundary))
                if end == -1:
                    break
            
            # 提取这部分内容
            part = post_data[start + len(boundary):end].strip()
            
            # 检查是否包含文件内容
            content_disposition = b'Content-Disposition: form-data;'
            if content_disposition in part:
                # 提取文件名
                filename_start = part.find(b'filename="')
                if filename_start != -1:
                    filename_start += 10  # len('filename="')
                    filename_end = part.find(b'"', filename_start)
                    if filename_end != -1:
                        filename = part[filename_start:filename_end]
                        filename = filename.decode('utf-8') if PY3 else filename
                        
                        # 只获取文件名，不要路径
                        filename = os.path.basename(filename)
                        
                        # 寻找文件内容开始位置（两个换行符之后）
                        content_start = part.find(b'\r\n\r\n')
                        if content_start != -1:
                            content_start += 4  # len('\r\n\r\n')
                            file_content = part[content_start:]
                            
                            # 保存文件
                            file_path = os.path.join(UPLOAD_DIR, filename)
                            with open(file_path, 'wb') as f:
                                f.write(file_content)
                            
                            print(f"已保存文件: {filename}")
                            return
            
            # 移动到下一部分
            start = end
        
        raise ValueError("无法找到或保存上传的文件")
    
    def generate_page(self, file_list):
        """生成HTML页面"""
        local_ip = get_local_ip()
        
        # 简单的HTML模板
        html = f"""<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>简易文件分享</title>
    <style>
        body {{
            font-family: 'Microsoft YaHei', Arial, sans-serif;
            max-width: 900px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f8f9fa;
        }}
        h1 {{
            color: #2c3e50;
            text-align: center;
        }}
        .info {{
            background-color: #e3f2fd;
            padding: 12px;
            border-radius: 5px;
            margin-bottom: 20px;
            text-align: center;
            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
        }}
        table {{
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
            background-color: white;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            border-radius: 5px;
            overflow: hidden;
        }}
        th, td {{
            padding: 12px 15px;
            text-align: left;
            border-bottom: 1px solid #eee;
        }}
        th {{
            background-color: #f5f5f5;
            font-weight: bold;
            color: #333;
        }}
        tr:hover {{
            background-color: #f9f9f9;
        }}
        .empty-message {{
            text-align: center;
            padding: 30px;
            color: #666;
            font-style: italic;
            background-color: white;
            border-radius: 5px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }}
        a {{
            color: #2196F3;
            text-decoration: none;
        }}
        a:hover {{
            text-decoration: underline;
        }}
        .delete-link {{
            color: #f44336;
            margin-left: 10px;
        }}
        form {{
            margin: 20px 0;
            padding: 20px;
            background-color: white;
            border-radius: 5px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }}
        input[type="file"] {{
            margin: 10px 0;
            width: 100%;
        }}
        input[type="submit"] {{
            background-color: #4CAF50;
            color: white;
            padding: 10px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
        }}
        input[type="submit"]:hover {{
            background-color: #45a049;
        }}
        .footer {{
            text-align: center;
            margin-top: 40px;
            color: #777;
            font-size: 14px;
        }}
    </style>
</head>
<body>
    <h1>简易文件分享</h1>
    
    <div class="info">
        文件分享地址: <strong>http://{local_ip}:{PORT}</strong>
        <div style="margin-top: 5px; font-size: 0.9em;">将此地址发送给他人，他们可以浏览和下载您分享的文件</div>
    </div>
    
    <form action="/upload" method="POST" enctype="multipart/form-data">
        <h3>上传新文件</h3>
        <input type="file" name="file" required>
        <input type="submit" value="上传">
    </form>
    
    <h3>文件列表</h3>
"""
        # 添加文件列表
        if file_list:
            file_info_list = []
            
            # 获取文件信息
            for filename in file_list:
                file_path = os.path.join(UPLOAD_DIR, filename)
                if os.path.isfile(file_path):
                    # 获取文件大小和修改时间
                    try:
                        size = os.path.getsize(file_path)
                        modified = os.path.getmtime(file_path)
                        
                        # 格式化文件大小
                        if size < 1024:
                            size_str = f"{size} B"
                        elif size < 1024 * 1024:
                            size_str = f"{size / 1024:.1f} KB"
                        elif size < 1024 * 1024 * 1024:
                            size_str = f"{size / (1024 * 1024):.1f} MB"
                        else:
                            size_str = f"{size / (1024 * 1024 * 1024):.1f} GB"
                        
                        # 格式化修改时间
                        import time
                        modified_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(modified))
                        
                        file_info_list.append({
                            'name': filename,
                            'size': size_str,
                            'modified': modified_str,
                            'url': urlparse.quote(filename) if PY3 else urlparse.quote(filename.encode('utf-8'))
                        })
                    except:
                        # 如果获取文件信息失败，使用基本信息
                        file_info_list.append({
                            'name': filename,
                            'size': '未知',
                            'modified': '未知',
                            'url': urlparse.quote(filename) if PY3 else urlparse.quote(filename.encode('utf-8'))
                        })
            
            # 创建表格
            html += """
    <table>
        <thead>
            <tr>
                <th>文件名</th>
                <th>大小</th>
                <th>修改时间</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
"""
            
            for file_info in file_info_list:
                html += f"""
        <tr>
            <td>{file_info['name']}</td>
            <td>{file_info['size']}</td>
            <td>{file_info['modified']}</td>
            <td>
                <a href="/uploads/{file_info['url']}">下载</a>
                <a href="/delete/{file_info['url']}" class="delete-link" onclick="return confirm('确定要删除文件 \'{file_info['name']}\' 吗?');">删除</a>
            </td>
        </tr>"""
            
            html += """
        </tbody>
    </table>
"""
        else:
            html += '<div class="empty-message">暂无文件，请上传文件开始分享</div>'
        
        html += """
    <div class="footer">
        简易文件分享工具 &copy; 2023
    </div>
</body>
</html>
"""
        return html

# 创建默认的index.html
def create_index_html():
    """创建默认的索引页面，重定向到根目录"""
    with open('index.html', 'w', encoding='utf-8') as f:
        f.write("""<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="refresh" content="0; url=/">
    <title>重定向中...</title>
</head>
<body>
    <p>重定向中，请稍候...</p>
</body>
</html>
""")

def run_server():
    """启动服务器"""
    # 创建索引页面
    create_index_html()
    
    # 获取IP地址
    ip = get_local_ip()
    
    # 启动服务器
    server_address = ('', PORT)
    httpd = HTTPServer(server_address, FileShareHandler)
    
    print("=" * 60)
    print("简易文件分享工具 - 简化版")
    print("=" * 60)
    print(f"服务器已启动，正在监听端口 {PORT}")
    print(f"您可以通过以下地址访问：")
    print(f"- 本机访问: http://localhost:{PORT}")
    print(f"- 局域网访问: http://{ip}:{PORT}")
    print("\n所有文件将保存在 '{UPLOAD_DIR}' 目录中")
    print("按 Ctrl+C 停止服务器...")
    print("=" * 60)
    
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("\n服务器已停止")

if __name__ == "__main__":
    run_server() 